package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func httpGetBody(url string) (interface{}, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

type Memo struct {
	f     Func
	cache map[string]result
}

type Func func(key string) (interface{}, error)

type result struct {
	value interface{}
	err   error
}

func New(f Func) *Memo {
	return &Memo{f: f, cache: make(map[string]result)}
}

func (m *Memo) Get(key string) (interface{}, error) {
	resp, ok := m.cache[key]
	if !ok {
		resp.value, resp.err = m.f(key)
		m.cache[key] = resp
	}
	return resp.value, resp.err
}

func main() {
	incomingURLs := []string{
		"https://mirrors.tuna.tsinghua.edu.cn",
		"https://mirrors.cloud.tencent.com",
		"https://developer.aliyun.com/mirror",
	}
	m := New(httpGetBody)
	for i := 0; i < 3; i++ {
		for _, url := range incomingURLs {
			start := time.Now()
			value, err := m.Get(url)
			if err != nil {
				log.Print(err)
			}
			fmt.Printf("%s, %s, %d bytes\n", url, time.Since(start), len(value.([]byte)))
		}
		fmt.Println()
	}

}
